#ifndef __SWARMDEPS_HPP__
#define __SWARMDEPS_HPP__

#include "SWARMTaskTagWrapper.hpp"

#include "../support/Threading.hpp"
#include "../support/Timing.hpp"
#include "../common/constants.h"
#include "../common/ComputePredsHelper.hpp"

#include "../simple_expression_template/VAR.hpp"
#include "../simple_expression_template/TERM.hpp"
#include "../simple_expression_template/EXPRESSION.hpp"
#include "../simple_expression_template/ADD.hpp"
#include "../simple_expression_template/SUB.hpp"
#include "../simple_expression_template/MIN.hpp"
#include "../simple_expression_template/MAX.hpp"
#include "../simple_expression_template/CEIL.hpp"
#include "../simple_expression_template/FLOOR.hpp"
#include "../simple_expression_template/SHIFTR.hpp"
#include "../simple_expression_template/SHIFTL.hpp"
#include "../simple_expression_template/GE.hpp"
#include "../simple_expression_template/LE.hpp"
#include "../simple_expression_template/FOR.hpp"


#include "../common/RuntimeWrapper.hpp"
#include "../common/TupleHelper.hpp"
#include "../common/DependenceGenerator.hpp"

#include <cassert>

template<typename THISDECL, typename CODELETDECL, typename SWARM_TAGTABLE>
class SWARMRuntimeWrapper : public RuntimeWrapper {
  bool asyncGetGenerated;
  THISDECL &THISINST;
  CODELETDECL &CODELETINST;
  SWARM_TAGTABLE &TAGTABLEINST;
public:
  SWARMRuntimeWrapper(THISDECL &tt, CODELETDECL &cc,  SWARM_TAGTABLE &sttt) : 
    asyncGetGenerated(false), THISINST(tt), CODELETINST(cc), TAGTABLEINST(sttt) {}

  // Async get in SWARM, therefore, need to copy the tag and have a
  // copy_tag != this_tag 
  template <typename TAG_TYPE>
  static inline TAG_TYPE &makeAsyncTagCopy(TAG_TYPE &this_tag) {
    TAG_TYPE *res = new TAG_TYPE(this_tag);
    return *res;
  }

  // Async get in SWARM, therefore, need to copy the tag and have a
  // copy_tag != this_tag 
  template <typename TAG_TYPE>
  inline void get(TAG_TYPE &this_tag, TAG_TYPE &copy_tag, void *&) {
#ifdef MEASURE_OVERHEADS
    Timer oh(GlobalTimers::Singleton().getOverheadSWARMGetPut());
#endif // MEASURE_OVERHEADS

    SwarmTagWrapper<TAG_TYPE> stw(&copy_tag);

#ifdef DEBUG
    SEQUENTIAL_DUMP1("Start get codelet on wrapper @" << &stw << " with tag " << copy_tag);
    SEQUENTIAL_DUMP1("Then requeue youserlf with tag " << this_tag);
#endif

    swarm_TagTable_get(&TAGTABLEINST, stw._cast_toIdentifiable(),
                       &CODELETINST, THISINST);
  }

  template<typename TAG_TYPE>
  inline bool markedAsyncGet(TAG_TYPE &t, int d) {
    return asyncGetGenerated || t.m_btt[d];
  }

  inline bool markedAsyncGet() {
    return asyncGetGenerated;
  }

  template<typename TAG_TYPE>
  inline void markAsyncGet(TAG_TYPE &this_tag, int i) {
#ifdef DEBUG
    SEQUENTIAL_DUMP1("Mark async get from tag " << this_tag) ;
#endif
    asyncGetGenerated = true;
    this_tag.m_btt[i] = true;
  }

  template <typename TAG_TYPE>
  inline void getZero(TAG_TYPE &, void *&) {
    // Don't do getZero atm
    // TBD
    assert(false);
  }

  template <typename TAG_TYPE>
  inline void depends(TAG_TYPE &) {
    // TBD
    assert(false);
  }

  template <typename TAG_TYPE>
  inline void dependsZero(TAG_TYPE &) {
    // TBD
    assert(false);
  }
};

template<int TASK_ID, int TASKTAGDIM, int INTERTASKDIM> 
using SWARMDeps = DependenceGenerator<TASK_ID, TASKTAGDIM, INTERTASKDIM, INTERTASKDIM>;
#endif // __SWARMDEPS_HPP__
